<template>
  <div class="validate-input-container pb-3">
    <input
      class="form-control"
      :class="{ 'is-invalid': inputRef.error === true }"
      aria-describedby="emailHelp"
      :value="inputRef.val"
      @blur="validateInput"
      @input="updateValue"
      v-bind="$attrs"
      v-if="inputType === 'input'"
    />
    <textarea
      v-else
      class="form-control"
      :class="{ 'is-invalid': inputRef.error === true }"
      style="height: 240px"
      aria-describedby="emailHelp"
      :value="inputRef.val"
      @blur="validateInput"
      @input="updateValue"
      v-bind="$attrs"
    ></textarea>
    <div
      id="validationServer03Feedback"
      class="invalid-feedback"
      v-if="inputRef.error"
    >
      {{ inputRef.message }}
    </div>
  </div>
</template>
<script lang='ts'>
import { defineComponent, PropType, reactive, onMounted, watch } from "vue";
// 导入已经创建好的侦听器
import { emitter } from "./ValidateForm.vue";
export interface RuleProp {
  type: "required" | "email" | "custom";
  message: string;
  validator?: () => boolean;
}
export default defineComponent({
  name: "ValidateInput",
  props: {
    rules: Array as PropType<RuleProp[]>,
    modelValue: String,
    inputType: String,
  },
  inheritAttrs: false,
  components: {},
  setup(props, context) {
    const emailReg =
      /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
    const inputRef = reactive({
      val: props.modelValue || "", // 和输入框的值对应
      error: false, // 输入验证是否通过
      message: "", // 输入验证没通过显示的信息
    });
    // 发现modelValue有值，但是没有赋值给inputRef.val。有可能是因为定义inputRef.的时候，modelValue还没传过来
    // 可以写一个监听属性，当modelValue有值了，就赋值
    watch(
      () => props.modelValue,
      () => {
        if (props.modelValue) {
          inputRef.val = props.modelValue;
        }
      }
    );
    // 这一通操作完，父组件可以直接通过v-model实现双向数据绑定
    const updateValue = (e: KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value;
      inputRef.val = targetValue;
      context.emit("update:modelValue", targetValue);
    };

    const validateInput = () => {
      // 判断一下 有没有传过来的值
      if (props.rules) {
        // 每一项验证都通过才通过---> 使用数组的every方法
        const allPassed = props.rules.every((rule) => {
          let passed = true;
          // 先将错误提示信息赋值到本地变量
          inputRef.message = rule.message;
          // 用switch便于后期加验证条件时扩展
          switch (rule.type) {
            case "required":
              // 输入框有值 就表示通过required验证
              passed = inputRef.val.trim() != "";
              break;
            case "email":
              // 判断是否符合正则表达式
              passed = emailReg.test(inputRef.val);
              break;
            default:
              break;
          }
          return passed;
        });
        // 通过error来控制message显示与否and输入框的样式
        inputRef.error = !allPassed;
        return allPassed;
      }
      return true;
    };
    onMounted(() => {
      // 传送验证函数validateInput的实体
      emitter.emit("form-item-created", validateInput);
    });
    return {
      inputRef,
      validateInput,
      updateValue,
    };
  },
});
</script>
<style scoped>
</style>